/*
 * This file is part of algowala.
 *
 * algowala is copyright (c) 2012 Jagannathan Sampath <algowala@jagernot.com>
 *
 * algowala is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * algowala is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with algowala.  If not, see <http://www.gnu.org/licenses/>.
 *
*/
#include "aw_thread.h"
#include "chrono.h"
#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;

extern chrono clk;

static const int buf_size = 1024;
static char buf [buf_size];

void* aw_thread::run (void* arg) {
    
  aw_thread* pt = static_cast<aw_thread*> (arg);
    
  while (1) {
    
    switch (aw_thread::opcode) {
      
      case aw_thread::quit: // quit 
        //cout << "quit: " << pt << endl;
        return 0;
      
      case aw_thread::tick: // tick stocks of this thread
        for (stock_iterator siter = pt->stocks.begin (), sjter = pt->stocks.end (); siter != sjter; ++siter) {
          stock& si = *siter;
          //cout << "tick: " << &si << endl;
          si.tick (clk.secs);
        } 
        break;
        
      case aw_thread::add: // add stock to this thread
        if (&pt->th == aw_thread::add_th) { 
          pt->stocks.push_back (aw_thread::added_stock);
          ++pt->num_stocks;
          aw_thread::added = 1;
          aw_thread::opcode = aw_thread::tick;
          //cout << "aw_thread::add " << aw_thread::added_stock.symbol << " to: " << aw_thread::add_th << endl;
        }
        break;
        
      case aw_thread::remove: // remove stock matching symbol
        if (!pt->checked) {
          for (stock_iterator i = pt->stocks.begin (), j = pt->stocks.end (); i != j;) {
            stock& si = *i;
            if (si.symbol == aw_thread::remove_sym) {
              i = pt->stocks.erase (i);
              pt->checked = 1;
            } else ++i;
          }
          pt->checked = 1;
        }
        break;
        
      case aw_thread::edit: // edit params of stock matching symbol
      
        if (!pt->checked) {
          for (stock_iterator i = pt->stocks.begin (), j = pt->stocks.end (); i != j; ++i) {
            stock& si = *i;
            if (si.symbol == aw_thread::edit_sym) {

              /*sprintf (buf, "%s %s %.2f %.2f %d %d", si.symbol.c_str(), si.company.c_str(), si.price, si.volatility, si.n_times, si.m_secs);
              cout << "matched_edit: " << buf << endl;*/
              
              if (aw_thread::edit_what & aw_thread::sym) {
                si.symbol = aw_thread::edit_stock.symbol;
                si.company = aw_thread::edit_stock.company;
              }
              
              if (aw_thread::edit_what & aw_thread::price) {
                si.price.value = aw_thread::edit_stock.price.value;
              }

              if (aw_thread::edit_what & aw_thread::volatility) {
                si.price.set_volatility (aw_thread::edit_stock.price.volatility);
              }
              
              if (aw_thread::edit_what & aw_thread::volume) {
                si.volume.value = aw_thread::edit_stock.volume.value;
              }

              if (aw_thread::edit_what & aw_thread::volume_volatility) {
                si.volume.set_volatility (aw_thread::edit_stock.volume.volatility);
              }

              if (aw_thread::edit_what & aw_thread::n_times) {
                si.n_times = aw_thread::edit_stock.n_times;
                si.calc_update_time ();
              }
              
              if (aw_thread::edit_what & aw_thread::m_secs) {
                si.m_secs = aw_thread::edit_stock.m_secs;
                si.calc_update_time ();
              }
              
            }
          } 
          pt->checked = 1;
        }
        break;
        
      case aw_thread::get:
        if (!pt->checked) {
          for (stock_iterator i = pt->stocks.begin (), j = pt->stocks.end (); i != j; ++i) {
            stock& si = *i;
            if (si.symbol == aw_thread::get_sym) {
              sprintf (buf, "%s %s %.2f %.2f %d %d %d %d", si.symbol.c_str(), si.company.c_str(), si.price.value, si.price.volatility, si.volume.value, si.volume.volatility, si.n_times, si.m_secs);
              //cout << "match: " << buf << endl;
              aw_thread::get_result = buf;
              break;
            }
          }
          pt->checked = 1;
        }
        break;
        
      case aw_thread::draw: // authorise draw
        aw_thread::opcode = aw_thread::tick;
        aw_thread::ok_draw = 1;
        break;
    
    }
    
    usleep (1);
    
  }
  
  return 0;
  
}

void aw_thread::add_stock (vector<aw_thread>& threads, const stock& _stock) {
  
  while (aw_thread::opcode != aw_thread::tick) usleep (1);  
  if (++aw_thread::add_rr >= threads.size ()) aw_thread::add_rr = 0;
  aw_thread::added = 0;
  aw_thread::added_stock = _stock;
  aw_thread::add_th = &threads [aw_thread::add_rr].th;
  aw_thread::opcode = aw_thread::add;
  while (aw_thread::added == 0) usleep (1);
  aw_thread::opcode = aw_thread::tick;
  
}
